#ifndef __XDO_01__
#define __XDO_01__

#include "../util/utils.pe.h"

namespace xm
{
	class XdoXPackA : public IKDetector, UnkBase
	{
	public:
		UNKNOWN_IMP1(IKDetector);
		DEFAULT_INIT_CLASS();
		STDMETHOD(Detect)( IKDetectSession * sess, DetectResult * pdr )
		{
			xm::iptr<IPeReader> winpe( sess->CurrentArchive() );
			if( !winpe ) return E_FAIL;

			if( winpe->IsWow64() ) return E_FAIL;

			UINT32 uCase = FALSE;
			RFAILED( TestCompilerSectionTable( winpe, uCase ) );
			RASSERT( !uCase, E_FAIL );

			DWORD dwInfMask = 0, iEntrySectId = 0;
			RFAILED( TestInfectOrPacked( winpe, dwInfMask, &iEntrySectId ) );

			if( dwInfMask ) return E_FAIL;
			if( iEntrySectId == (DWORD)-1 ) return E_FAIL;

			IPeReader::TImgSecHdr * hdr = winpe->SectionHeader(iEntrySectId);
			if( !hdr ) return E_FAIL;

			bool_t isVB = SUCCEEDED(TestMSVB(winpe)); 
			size_t sizeOfRawData = hdr->SizeOfRawData;

			size_t MinRawSize = isVB ? 48 * 1024 : 64 * 1024;
			size_t MaxRawSize = 768*1024;

			if( sizeOfRawData < MinRawSize ) return E_FAIL;
			if( sizeOfRawData > MaxRawSize ) return E_FAIL;

			iptr<IKPETools> petool;
			RFAILED( get_this_pe_tools( sess,winpe,petool.pp() ) );

			if( petool->IsMoudleImported( "iertutil.dll,msdmo.dll,msi.dll,wintrust.dll", ModuleNameInKeyStr ) )
				//petool->IsMoudleImported( "msdmo.dll", KeyStrInModuleName ) ||
				//petool->IsMoudleImported( "msi.dll", KeyStrInModuleName ) ||
				//petool->IsMoudleImported( "wintrust.dll", KeyStrInModuleName ) )
				return E_FAIL;


			iptr<IKFileStream> stm( sess->TargetStream() );
			RFAILED( stm->SetPos( hdr->PointerToRawData ) );

			CalcCodeRate codeRate;

			iptr<IKBCoderLL> oCoder( "DeflateCoderLL" );
			RASSERT( oCoder, E_FAIL );

			//SIZE_T calcSize = MIN( sizeOfRawData, 0x4000 );
			RFAILED( CodeTo<0x4000>( oCoder, stm, sizeOfRawData, &codeRate ) );

			DOUBLE rate = codeRate.GetRate();

			BOOL bImpMFC = SUCCEEDED(petool->IsMoudleImported( "MFC42", KeyStrInModuleName ) );

			//printf( "[ VB=%d,Rate=%g ]", isVB?1:0, rate );

			DOUBLE line = 0.82999;
			if( isVB ) line = 0.55;
			if( bImpMFC ) line = 0.71;

			if( rate < line ) return E_FAIL;

			pdr->Level = DLEV_MALW_HEUR;
			if( rate > 0.92 ) pdr->Level = DLEV_MALW_EXACT;
			else if( rate > 0.7 && isVB ) pdr->Level = DLEV_MALW_EXACT;
			else if( rate > 0.82 && bImpMFC ) pdr->Level = DLEV_MALW_EXACT;

			return S_OK;
		}
		STDMETHOD(Treat)( IKDetectSession * ctx, DetectResult * pdr )
		{
			return ctx->RawStream()->Remove();
		}
		STDMETHOD(Reset)()
		{
			return S_OK;
		}
	};
};


#endif